package com.mzy.multithreading.lock.reentrantlock;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author mzy
 * @Date 2022/7/28 8:05
 * @Version 1.0
 */

import java.util.concurrent.locks.ReentrantLock;

/**
 * 可重入锁，重写卖票方案
 * 锁和sync的区别
 * <p>
 * Lock锁实现提供了比使用同步方法和语句更广泛的锁操作，
 * lock允许更灵活的结构，可以具有非常不同的属性，并且可能支持多个关联的条件对象。
 * lock提供比synchronized更多的功能。
 * 其次lock不是Java内置的，synchronize是Java语言内置的关键字。lock是类，通过类实现同步访问。
 * lock需要手动释放锁，synchronize不需要。
 * 其他： 1.lock可以让等待锁的线程响应终端，而synchronized却不行，使用synchronized时,等待的线程会
 * 一直等待下去，不能够响应终端；
 * 2.通过Lock可以知道有没有成功获取锁，而synchronized无法办到
 * 3.lock可以提供多个线程进行读写操作的效率。
 *
 * 在性能上，如果竞争资源不激烈，两者相差不大。如果竞争资源非常激烈（大量线程同时竞争），此时Lock的性能
 * 要远远优于synchronize。
 */
public class RLSaleTicket {

    // 第二步 创建多个线程，调用资源类的操作方法
    public static void main(String[] args) {
        RLTicket rlTicket = new RLTicket();

        // 创建三个线程
        new Thread( ()->{
            for (int i = 0; i < 40; i++) {
                rlTicket.sale();
            }
        },"AA").start();
        new Thread( ()->{
            for (int i = 0; i < 40; i++) {
                rlTicket.sale();
            }
        },"BB").start();
        new Thread( ()->{
            for (int i = 0; i < 40; i++) {
                rlTicket.sale();
            }
        },"CC").start();
    }

}

// 第一步 创建资源类，定义属性和操作方法
class RLTicket {
    // 票数量
    private int number = 30;

    // 创建可重入锁
    private final ReentrantLock lock = new ReentrantLock();

    // 卖票方法
    public void sale() {
        /**
         * 注意lock不会释放锁，所以需要在finally中执行释放
         */
        // 上锁
        lock.lock();

        try {
            // 判断是否有票
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + " : 卖出" + (number--) + "剩余：" + number);

            }
        } finally {
            // 解锁
            lock.unlock();
        }

    }
}
